home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Freeware / Miro 1.0 / Miro_Installer.exe / xulrunner / python / fileutil.py < prev    next >
Encoding:
Python Source  |  2007-11-12  |  4.7 KB  |  132 lines

  1. # Miro - an RSS based video player application
  2. # Copyright (C) 2005-2007 Participatory Culture Foundation
  3. #
  4. # This program is free software; you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation; either version 2 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program; if not, write to the Free Software
  16. # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  17.  
  18.  
  19. """Functions to handle moving/deleting files, especially on windows where file
  20. locking semantics can cause problems.
  21. """
  22.  
  23. import logging
  24. import os
  25. import shutil
  26.  
  27. import eventloop
  28.  
  29. def migrate_file(source, dest, callback, retry_after=10, retry_for=60):
  30.     """Try to migrate a file, if this works, callback is called.  If we fail
  31.     because the file is open, we retry migrating the file every so often (by
  32.     default every 10 seconds, stopping after 60 seconds).  This probably only
  33.     makes a difference on Windows.
  34.     """
  35.  
  36.     try:
  37.         shutil.move(source, dest)
  38.     except EnvironmentError, e:
  39.         logging.warn("Error migrating %s to %s (Error: %s)", source, dest, e)
  40.         try:
  41.             os.remove(dest)
  42.         except EnvironmentError:
  43.             pass
  44.         if retry_for > 0:
  45.             if e.errno == 13:
  46.                 # permission denied, assume this means it's open by another
  47.                 # process on windows.
  48.                 logging.info('Retrying migration')
  49.                 eventloop.addTimeout(retry_after, migrate_file, 
  50.                         "Migrate File Retry", args=(source, dest, callback,
  51.                             retry_after, retry_for - retry_after))
  52.     except TypeError, e:
  53.         logging.warn ("Type error migrating %s (%s) to %s (%s) (Error %s)",
  54.                 source, type(source), dest, type(dest), e)
  55.         raise
  56.     else:
  57.         callback()
  58.  
  59. class DeletesInProgressTracker(set):
  60.     def __init__(self):
  61.         self.set = set()
  62.     def normalize(self, path):
  63.         return os.path.abspath(os.path.normcase(path))
  64.     def add(self, path):
  65.         self.set.add(self.normalize(path))
  66.     def discard(self, path):
  67.         self.set.discard(self.normalize(path))
  68.     def __contains__(self, path):
  69.         return self.normalize(path) in self.set
  70.  
  71. deletes_in_progress = DeletesInProgressTracker()
  72.  
  73. def delete(path, retry_after=10, retry_for=60):
  74.     """Try to delete a file or directory.  If this fails because the file is
  75.     open, we retry deleting the file every so often This probably only makes a
  76.     difference on Windows.
  77.     """
  78.  
  79.     try:
  80.         if os.path.isfile(path):
  81.             os.remove (path)
  82.         elif os.path.isdir(path):
  83.             shutil.rmtree (path)
  84.     except EnvironmentError, e:
  85.         logging.warn("Error deleting %s", path)
  86.         if retry_for > 0 and e.errno == 13:
  87.             # permission denied, assume this means it's open by another
  88.             # process on windows.
  89.             deletes_in_progress.add(path)
  90.             logging.info('Retrying delete')
  91.             eventloop.addTimeout(retry_after, delete, 
  92.                     "Delete File Retry", args=(path, retry_after, 
  93.                         retry_for - retry_after))
  94.     else:
  95.         deletes_in_progress.discard(path)
  96.  
  97. def miro_listdir(directory):
  98.     """Directory listing that's safe and convenient for finding new videos in
  99.     a directory.
  100.  
  101.     Returns the tuple (files, directories) where both elements are a list of
  102.     absolute pathnames.  OSErrors are silently ignored.  Hidden files aren't
  103.     returned.  Pathnames are run through os.path.normcase.
  104.     """
  105.  
  106.     files = []
  107.     directories = []
  108.     directory = os.path.abspath(os.path.normcase(directory))
  109.     if directory in deletes_in_progress:
  110.         return
  111.     try:
  112.         listing = os.listdir(directory)
  113.     except OSError:
  114.         return [], []
  115.     for name in listing:
  116.         if name[0] == '.' or name.lower() == 'thumbs.db':
  117.             # thumbs.db is a windows file that speeds up thumbnails.  We know
  118.             # it's not a movie file.
  119.             continue
  120.         path = os.path.join(directory, os.path.normcase(name))
  121.         if path in deletes_in_progress:
  122.             continue
  123.         try:
  124.             if os.path.isdir(path):
  125.                 directories.append(path)
  126.             else:
  127.                 files.append(path)
  128.         except OSError:
  129.             pass
  130.     return files, directories
  131.  
  132.